﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using SilverCrmSoap.CrmSdk;
using SilverCrmSoap.Helpers;

namespace LookupControl
{
	public enum LookupStyle
	{
		Single,
		Multi
	}

	[DefaultEvent("LookupControlLoaded")]
	[ContentProperty("Items")]
	public partial class SilverCrmLookup : UserControl
	{
		private bool _isInitialized = false;
		private ImageSource _icon = null;
		private List<LookupItem> _items = new List<LookupItem>();
		private List<HyperlinkButton> _hlbuttons = new List<HyperlinkButton>();
		private LookupView _filteredView = new LookupView() { };
		private bool _lookupReadOnly = false;
		private int _oType = 0;
		private string _oTypeName = string.Empty;
		private bool _disableViewPicker = false;
		private bool _disableQuickFind = false;
		private bool _showNewButton = true;
		private bool _showPropButton = true;
		private bool _browse = false;
		private bool _allowFilterOff = true;
		private Guid _defaultViewId = Guid.Empty;
		private LookupStyle _lookupStyle;

		private List<HyperlinkButton> HlButtons { get { return _hlbuttons; } set { _hlbuttons = value; } }

		private bool _autoComplete = false;
		private string _searchAttribute = string.Empty;
		private string _primaryAttribute = string.Empty;

		public event RoutedEventHandler LookupOnValueChange;
		public event RoutedEventHandler LookupContentClick;
		public event RoutedEventHandler LookupControlLoaded;
		public event RoutedEventHandler LookupControlOnUserChangeValue;

		[Category("Lookup")]
		public ImageSource Icon { get { return _icon; } set { _icon = value; } }

		[Category("Lookup")]
		public bool DisableViewPicker { get { return _disableViewPicker; } set { _disableViewPicker = value; } }

		[Category("Lookup")]
		public bool DisableQuickFind { get { return _disableQuickFind; } set { _disableQuickFind = value; } }

		[Category("Lookup")]
		public bool ShowNewButton { get { return _showNewButton; } set { _showNewButton = value; } }

		[Category("Lookup")]
		public bool ShowPropButton { get { return _showPropButton; } set { _showPropButton = value; } }

		[Category("Lookup")]
		public bool Browse { get { return _browse; } set { _browse = value; } }

		[Category("Lookup")]
		public bool AllowFilterOff { get { return _allowFilterOff; } set { _allowFilterOff = value; } }

		[Category("Lookup")]
		public Guid DefaultViewId { get { return _defaultViewId; } set { _defaultViewId = value; } }

		public LookupView FilteredView { get { return _filteredView; } set { _filteredView = value; } }

		[Category("AutoComplete")]
		public string SearchAttribute { get { return _searchAttribute; } set { _searchAttribute = value; } }

		[Category("AutoComplete")]
		public string PrimaryAttribute { get { return _primaryAttribute; } set { _primaryAttribute = value; } }

		public static readonly DependencyProperty AutoCompleteProperty = DependencyProperty.Register(
			"AutoComplete",
			typeof(bool),
			typeof(SilverCrmLookup),
			new PropertyMetadata(false, OnAutoCompletePropertyChanged));

		[Category("AutoComplete")]
		public bool AutoComplete
		{
			get { return (GetValue(AutoCompleteProperty) as bool?).Value; }
			set
			{
				_autoComplete = value;
				SetValue(AutoCompleteProperty, value);
			}
		}

		/// <summary>
		/// AutoCompleteProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its AutoComplete.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnAutoCompletePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).AutoComplete = (e.NewValue as bool?).Value;
			}
		}

		public static readonly DependencyProperty MinimumPrefixLengthProperty = DependencyProperty.Register(
			"MinimumPrefixLength",
			typeof(int),
			typeof(SilverCrmLookup),
			new PropertyMetadata(1, OnMinimumPrefixLengthPropertyChanged));

		[Category("AutoComplete")]
		public int MinimumPrefixLength
		{
			get { return (GetValue(MinimumPrefixLengthProperty) as int?).Value; }
			set
			{
				this.autoCompleteBox.MinimumPrefixLength = value;
				SetValue(MinimumPrefixLengthProperty, value);
			}
		}

		/// <summary>
		/// MinimumPrefixLengthProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its MinimumPrefixLength.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnMinimumPrefixLengthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).MinimumPrefixLength = (e.NewValue as int?).Value;
			}
		}

		public ObservableCollection<object> IdList
		{
			get
			{
				ObservableCollection<object> ids = new ObservableCollection<object>();
				foreach (var item in this.Items)
				{
					ids.Add(item.Id);
				}
				return ids;
			}
		}

		public static DependencyProperty ItemsProperty = DependencyProperty.Register(
			"Items",
			typeof(List<LookupItem>),
			typeof(SilverCrmLookup),
			new PropertyMetadata(OnItemsPropertyChanged));

		public List<LookupItem> Items
		{
			get
			{
				if (GetValue(ItemsProperty) as List<LookupItem> != null)
				{
					return GetValue(ItemsProperty) as List<LookupItem>;
				}
				else
				{
					return new List<LookupItem>();
				}
			}
			set
			{
				if (value != null && value.Count > 0)
				{
					_items = value;
					SetValue(ItemsProperty, value);
					if (this.icoLookupIcon.Source == null)
						this.icoLookupIcon.Source = Icon;
					List<HyperlinkButton> hlbuttons = new List<HyperlinkButton>();
					foreach (var item in value)
					{
						item.Url = CombineUrl(XrmHelper.ServerUri, "/main.aspx?etc=" + this.ObjectTypeCode + "&id=" + item.Id.ToString() + "&pagetype=entityrecord").AbsoluteUri;
						HyperlinkButton hlbutton = new HyperlinkButton();
						hlbutton.Content = item.Name;
						hlbutton.NavigateUri = new Uri(item.Url);
						hlbuttons.Add(hlbutton);
					}
					domainUpDown1.ItemsSource = hlbuttons;
					if (this.Items.Count <= 1)
						domainCol.Width = new GridLength(0);
					else
						domainCol.Width = new GridLength(16);
					autoCompleteBox.Visibility = System.Windows.Visibility.Collapsed;
					lnkButton.Visibility = System.Windows.Visibility.Visible;
				}
				else
				{
					_items = new List<LookupItem>();
					SetValue(ItemsProperty, null);
					HlButtons = new List<HyperlinkButton>();
					domainCol.Width = new GridLength(0);
					this.icoLookupIcon.Source = null;
					domainUpDown1.ItemsSource = HlButtons;
				}
				if (LookupOnValueChange != null)
				{
					RoutedEventArgs e = new RoutedEventArgs();
					LookupOnValueChange(this, e);
				}
			}
		}

		/// <summary>
		/// ItemsProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its Items.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).Items = e.NewValue as List<LookupItem>;
			}
		}

		public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(
			"IsReadOnly",
			typeof(bool),
			typeof(SilverCrmLookup),
			new PropertyMetadata(false, OnIsReadOnlyPropertyChanged));

		[Category("Lookup")]
		public bool IsReadOnly
		{
			get { return (GetValue(IsReadOnlyProperty) as bool?).Value; }
			set
			{
				if (_lookupReadOnly != value)
				{
					_lookupReadOnly = value;
					if (value)
					{
						this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_dis_lookup.png", UriKind.Relative));
						this.btnLookupButton.MouseLeftButtonUp -= btnLookupButton_Click;
						this.icoLookupIcon.MouseLeftButtonUp -= lnkButton_Click;
						this.LayoutRoot.MouseLeftButtonDown -= LayoutRoot_MouseLeftButtonDown;
						this.btnLookupButton.MouseEnter -= new MouseEventHandler(btnLookupButton_MouseEnter);
						this.btnLookupButton.MouseLeave -= new MouseEventHandler(btnLookupButton_MouseLeave);
					}
					else
					{
						this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_off_lookup.png", UriKind.Relative));
						this.btnLookupButton.MouseLeftButtonUp += btnLookupButton_Click;
						this.icoLookupIcon.MouseLeftButtonUp += lnkButton_Click;
						this.LayoutRoot.MouseLeftButtonDown += LayoutRoot_MouseLeftButtonDown;
						this.btnLookupButton.MouseEnter += new MouseEventHandler(btnLookupButton_MouseEnter);
						this.btnLookupButton.MouseLeave += new MouseEventHandler(btnLookupButton_MouseLeave);
					}
					SetValue(IsReadOnlyProperty, value);
				}
			}
		}

		/// <summary>
		/// IsReadOnlyProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its IsReadOnly.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnIsReadOnlyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).IsReadOnly = (e.NewValue as bool?).Value;
			}
		}

		public static readonly DependencyProperty ObjectTypeCodeProperty = DependencyProperty.Register(
			"ObjectTypeCode",
			typeof(int),
			typeof(SilverCrmLookup),
			new PropertyMetadata(0, OnObjectTypeCodePropertyChanged));

		[Browsable(false)]
		public int ObjectTypeCode { get { return (GetValue(ObjectTypeCodeProperty) as int?).Value; } set { _oType = (string.IsNullOrEmpty(value.ToString())) ? 0 : value; SetValue(ObjectTypeCodeProperty, value); } }

		/// <summary>
		/// ObjectTypeCodeProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its ObjectTypeCode.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnObjectTypeCodePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).ObjectTypeCode = (e.NewValue as int?).Value;
			}
		}

		[Category("Lookup")]
		public LookupStyle LookupStyle { get { return _lookupStyle; } set { _lookupStyle = value; } }

		public static readonly DependencyProperty EntityNameProperty = DependencyProperty.Register(
			"EntityName",
			typeof(string),
			typeof(SilverCrmLookup),
			new PropertyMetadata(string.Empty, OnEntityNamePropertyChanged));

		[Category("Lookup")]
		public string EntityName
		{
			get { return GetValue(EntityNameProperty) as string; }
			set
			{
				_oTypeName = value.ToLower();
				SetValue(EntityNameProperty, value.ToLower());
			}
		}

		/// <summary>
		/// EntityNameProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its EntityName.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnEntityNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).EntityName = e.NewValue as string;
			}
		}

		public new static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register(
			"IsEnabled",
			typeof(bool),
			typeof(SilverCrmLookup),
			new PropertyMetadata(true, OnIsEnabledPropertyChanged));

		[Category("Lookup")]
		public new bool IsEnabled
		{
			get { return (GetValue(IsEnabledProperty) as bool?).Value; }
			set
			{
				if (value != base.IsEnabled)
				{
					if (!value)
					{
						this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_dis_lookup.png", UriKind.Relative));
						this.btnLookupButton.MouseLeftButtonUp -= btnLookupButton_Click;
						this.lnkButton.Click -= lnkButton_Click;
						this.icoLookupIcon.MouseLeftButtonUp -= lnkButton_Click;
						this.LayoutRoot.MouseLeftButtonDown -= LayoutRoot_MouseLeftButtonDown;
						this.btnLookupButton.MouseEnter -= new MouseEventHandler(btnLookupButton_MouseEnter);
						this.btnLookupButton.MouseLeave -= new MouseEventHandler(btnLookupButton_MouseLeave);
					}
					else
					{
						this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_off_lookup.png", UriKind.Relative));
						this.btnLookupButton.MouseLeftButtonUp += btnLookupButton_Click;
						this.lnkButton.Click += lnkButton_Click;
						this.icoLookupIcon.MouseLeftButtonUp += lnkButton_Click;
						this.LayoutRoot.MouseLeftButtonDown += LayoutRoot_MouseLeftButtonDown;
						this.btnLookupButton.MouseEnter += new MouseEventHandler(btnLookupButton_MouseEnter);
						this.btnLookupButton.MouseLeave += new MouseEventHandler(btnLookupButton_MouseLeave);
					}
					base.IsEnabled = value;
					SetValue(IsEnabledProperty, value);
				}
			}
		}

		/// <summary>
		/// IsEnabledProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its IsEnabled.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).IsEnabled = (e.NewValue as bool?).Value;
			}
		}

		public new static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register(
			"BorderThickness",
			typeof(Thickness),
			typeof(SilverCrmLookup),
			new PropertyMetadata(new Thickness(1), OnBorderThicknessPropertyChanged));

		public new Thickness BorderThickness
		{
			get { return (GetValue(BorderThicknessProperty) as Thickness?).Value; }
			set
			{
				this.border.BorderThickness = value;
				SetValue(BorderThicknessProperty, value);
			}
		}

		/// <summary>
		/// BorderThicknessProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its BorderThickness.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnBorderThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).BorderThickness = (e.NewValue as Thickness?).Value;
			}
		}

		public new static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
			"Background",
			typeof(Brush),
			typeof(SilverCrmLookup),
			new PropertyMetadata(new SolidColorBrush(Colors.White), OnBackgroundPropertyChanged));

		[Category("Brushes")]
		public new Brush Background
		{
			get { return GetValue(BackgroundProperty) as Brush; }
			set
			{
				this.LayoutRoot.Background = value;
				this.autoCompleteBox.Background = value;
				SetValue(BackgroundProperty, value);
			}
		}

		/// <summary>
		/// BorderThicknessProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its BorderThickness.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnBackgroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).Background = e.NewValue as Brush;
			}
		}

		public static readonly DependencyProperty FocusBackgroundProperty = DependencyProperty.Register(
			"FocusBackground",
			typeof(Brush),
			typeof(SilverCrmLookup),
			new PropertyMetadata(new SolidColorBrush(Color.FromArgb(255, 200, 210, 255)), OnFocusBackgroundPropertyChanged));

		[Category("Brushes")]
		public Brush FocusBackground
		{
			get { return GetValue(FocusBackgroundProperty) as Brush; }
			set
			{
				SetValue(FocusBackgroundProperty, value);
			}
		}

		/// <summary>
		/// FocusBackgroundProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its FocusBackground.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnFocusBackgroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).FocusBackground = e.NewValue as Brush;
			}
		}

		public new static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register(
			"BorderBrush",
			typeof(Brush),
			typeof(SilverCrmLookup),
			new PropertyMetadata(new SolidColorBrush(Colors.LightGray), OnBorderBrushPropertyChanged));

		[Category("Brushes")]
		public new Brush BorderBrush
		{
			get { return GetValue(BorderBrushProperty) as Brush; }
			set
			{
				this.border.BorderBrush = value;
				SetValue(BorderBrushProperty, value);
			}
		}

		/// <summary>
		/// BorderBrushProperty property changed handler.
		/// </summary>
		/// <param name="d">LookupControl that changed its BorderBrush.</param>
		/// <param name="e">Event arguments.</param>
		private static void OnBorderBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (e.OldValue != e.NewValue)
			{
				(d as SilverCrmLookup).BorderBrush = e.NewValue as Brush;
			}
		}

		public SilverCrmLookup()
		{
			InitializeComponent();
		}

		private void RaiseLookupButtonClick(RoutedEventArgs e)
		{
			OpenLookup();
		}

		private void OpenLookup()
		{
			if (this.FilteredView == null) { this.FilteredView = new LookupView() { DisplayName = string.Empty, FetchXml = string.Empty, LayoutXml = string.Empty, ObjectTypeCode = string.Empty, ViewId = Guid.Empty }; }
			bool isFiltered = !string.IsNullOrEmpty(this.FilteredView.FetchXml);
			string ids = string.Empty;
			string names = string.Empty;
			foreach (var item in this.Items)
			{
				ids += item.Id.ToString() + "|";
				names += item.Name + "|";
			}
			string defaultView = (isFiltered) ? "&defaultViewId={" + this.FilteredView.ViewId.ToString().ToUpper() + "}" : (_defaultViewId != Guid.Empty) ? "&defaultViewId={" + this.DefaultViewId.ToString().ToUpper() + "}" : string.Empty;
			string disableViewPicker = _disableViewPicker ? "1" : "0";
			string disableQuickFind = _disableQuickFind ? "1" : "0";
			string showNewButton = _showNewButton ? "1" : "0";
			string showPropButton = _showPropButton ? "1" : "0";
			string browse = _browse ? "1" : "0";
			string allowFilterOff = _allowFilterOff ? "1" : "0";
			string lookupUrl = CombineUrl(XrmHelper.ServerUri, "/_controls/lookup/lookupinfo.aspx?AllowFilterOff=" + allowFilterOff + "&DefaultType=" + this.ObjectTypeCode + "&DisableQuickFind=" + disableQuickFind + "&DisableViewPicker=" + disableViewPicker + "&LookupStyle=" + this.LookupStyle.ToString() + "&ShowNewButton=" + showNewButton + "&ShowPropButton=" + showPropButton + "&browse=" + browse + "&objecttypes=" + this.ObjectTypeCode + defaultView).AbsoluteUri;
			StringBuilder sb = new StringBuilder();
			sb.Append(string.Format(@"
					oArg = {{
						items: null,
						customViews: null,
						setCustomView: function (viewId, entityName, viewDisplayName, fetchXml, layoutXml) {{
							customView = {{
								recordType: entityName,
								id: viewId,
								name: viewDisplayName,
								fetchXml: fetchXml,
								layoutXml: layoutXml
							}};
							this.customViews=new Array();
							this.customViews[0] = customView;
						}},

						setLookupItems: function (ids, names, type) {{
							var idArr = ids.split('|');
							var nameArr = names.split('|');
							this.items=new Array();
							for (var i = 0; i < idArr.length; i++) {{
								if (idArr[i].length >= 32) {{
									this.items[i] = {{
										oid: idArr[i],
										outerText: nameArr[i],
										oType: type,
										getAttribute: function (value) {{
											switch (value) {{
												case 'oid':
													{{
														return this.oid;
													}}
												case 'otype':
													{{
														return this.oType;
													}}
												default:
													{{
														return null;
													}}
											}}
										}}
									}};
								}}
							}}
						}}
					}};

					function fun1() {{
						oArg.setLookupItems(""{0}"", ""{1}"", ""{2}"");
						if({3}){{
							oArg.setCustomView(""{4}"",""{5}"",""{6}"",""{7}"",""{8}"");
						}}
						var lookupItems = window.showModalDialog('{9}', oArg, 'resizable:yes;');
						if (lookupItems != window.undefined)
							var returnValue = new Array(lookupItems.items.length);
						if (lookupItems != window.undefined) {{
							for (i = 0; i < lookupItems.items.length; i++) {{
								returnValue[i] = new Array(2);
								returnValue[i][0] = lookupItems.items[i].id;
								returnValue[i][1] = lookupItems.items[i].name;
							}}
						}}
						return returnValue;
					}} fun1();", ids, names.Replace("\"", "\\\""), this.ObjectTypeCode.ToString(), isFiltered.ToString().ToLower(), "{" + this.FilteredView.ViewId.ToString().ToUpper() + "}", this.FilteredView.ObjectTypeCode, this.FilteredView.DisplayName, this.FilteredView.FetchXml, this.FilteredView.LayoutXml, lookupUrl)
			);
			ScriptObject result = (ScriptObject)HtmlPage.Window.Eval(sb.ToString());
			if (result != null)
			{
				Array arr = result.ConvertTo<Array>();
				List<LookupItem> items = new List<LookupItem>();
				if (arr.Length > 0)
				{
					for (int i = 0; i < arr.Length; i++)
					{
						Array ar2 = (Array)arr.GetValue(i);
						LookupItem item = new LookupItem { Id = new Guid(ar2.GetValue(0).ToString()), Name = ar2.GetValue(1).ToString() };
						items.Add(item);
					}
				}
				Items = items;
				if (_autoComplete && items.Count == 0)
				{
					//autoCompleteBox.Visibility = System.Windows.Visibility.Visible;
					//autoCompleteBox.Width = innerGrid.ActualWidth;
					//autoCompleteBox.SelectedItem = null;
					//autoCompleteBox.Text = string.Empty;
					//lnkButton.Visibility = System.Windows.Visibility.Collapsed;
					//autoCompleteBox.Focus();
				}
				if (LookupControlOnUserChangeValue != null)
				{
					LookupControlOnUserChangeValue(this, new RoutedEventArgs());
				}
			}
		}

		private void RaiseLookupContentClick(RoutedEventArgs e, string url)
		{
			if (LookupContentClick != null)
			{
				LookupContentClick(this, e);
			}
			else
			{
				OpenRecord(url);
			}
		}

		private void OpenRecord(string url)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append(string.Format(@"window.open('{0}','record','status=yes,toolbar=no,menubar=no,location=no,resizable=yes');", url));
			HtmlPage.Window.Eval(sb.ToString());
		}

		private void btnLookupButton_Click(object sender, RoutedEventArgs e)
		{
			RaiseLookupButtonClick(e);
		}

		private void lnkButton_Click(object sender, RoutedEventArgs e)
		{
			HyperlinkButton button = (HyperlinkButton)domainUpDown1.Value;
			RaiseLookupContentClick(e, button.NavigateUri.AbsoluteUri.ToString());
		}

		private void btnLookupButton_MouseLeave(object sender, MouseEventArgs e)
		{
			if (!IsReadOnly)
				btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_off_lookup.png", UriKind.Relative));
		}

		private void btnLookupButton_MouseEnter(object sender, MouseEventArgs e)
		{
			if (!IsReadOnly)
				btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_on_lookup.png", UriKind.Relative));
		}

		private void StackPanel_GotFocus(object sender, RoutedEventArgs e)
		{
			LayoutRoot.Background = this.FocusBackground;
			if (_autoComplete && this.Items.Count == 0)
			{
				if (IsEnabled && !IsReadOnly)
				{
					autoCompleteBox.Visibility = System.Windows.Visibility.Visible;
					autoCompleteBox.Width = innerGrid.ActualWidth;
					autoCompleteBox.SelectedItem = null;
					autoCompleteBox.Text = string.Empty;
					//autoCompleteBox.Focus();
					lnkButton.Visibility = System.Windows.Visibility.Collapsed;
				}
			}
		}

		private void ctrlLookup_LostFocus(object sender, RoutedEventArgs e)
		{
			LayoutRoot.Background = this.Background;
		}

		private void LayoutRoot_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Delete)
			{
				this.Items = new List<LookupItem>();
				if (_autoComplete)
				{
					autoCompleteBox.Visibility = System.Windows.Visibility.Visible;
					autoCompleteBox.Width = innerGrid.ActualWidth;
					autoCompleteBox.SelectedItem = null;
					autoCompleteBox.Text = string.Empty;
					lnkButton.Visibility = System.Windows.Visibility.Collapsed;
					autoCompleteBox.Focus();
				}
			}
		}

		private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			base.OnMouseLeftButtonDown(e);
			Focus();
		}

		private void ReportError(Exception ex)
		{
			this.ReportMessage("Exception: " + ex.Message + "\n" + ex.StackTrace);
		}

		private void ReportMessage(string message)
		{
			this.Dispatcher.BeginInvoke(() => HtmlPage.Window.Alert(message));
		}

		private void LoadEntity()
		{
			if (EntityName != string.Empty)
			{
				try
				{
					SoapHelper.BeginExecuteRetrieveEntity(EntityName, new AsyncCallback(RetrieveEntity_Callback));
				}
				catch (Exception ex)
				{
					this.ReportError(ex);
				}
			}
		}

		private void RetrieveEntity_Callback(IAsyncResult result)
		{
			try
			{
				OrganizationResponse response = ((IOrganizationService)result.AsyncState).EndExecute(result);
				EntityMetadata entity = (EntityMetadata)response["EntityMetadata"];

				if (entity == null)
				{
					this.ReportMessage("entity not found : " + EntityName);
				}
				else
				{
					Dispatcher.BeginInvoke(() => this.ObjectTypeCode = entity.ObjectTypeCode.Value);
					Dispatcher.BeginInvoke(() => LookupLoaded());
				}
			}
			catch (Exception ex)
			{
				this.ReportError(ex);
			}
		}

		private void LookupLoaded()
		{
			if (!_isInitialized)
			{
				if (!IsEnabled)
				{
					this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_dis_lookup.png", UriKind.Relative));
					this.btnLookupButton.MouseLeftButtonUp -= btnLookupButton_Click;
					this.lnkButton.Click -= lnkButton_Click;
					this.btnLookupButton.MouseLeftButtonUp -= btnLookupButton_Click;
					this.LayoutRoot.MouseLeftButtonDown -= LayoutRoot_MouseLeftButtonDown;
					this.btnLookupButton.MouseEnter -= new MouseEventHandler(btnLookupButton_MouseEnter);
					this.btnLookupButton.MouseLeave -= new MouseEventHandler(btnLookupButton_MouseLeave);
				}
				else if (_lookupReadOnly)
				{
					this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_dis_lookup.png", UriKind.Relative));
					this.btnLookupButton.MouseLeftButtonUp -= btnLookupButton_Click;
					this.lnkButton.Click += lnkButton_Click;
					this.btnLookupButton.MouseLeftButtonUp -= btnLookupButton_Click;
					this.LayoutRoot.MouseLeftButtonDown -= LayoutRoot_MouseLeftButtonDown;
					this.btnLookupButton.MouseEnter -= new MouseEventHandler(btnLookupButton_MouseEnter);
					this.btnLookupButton.MouseLeave -= new MouseEventHandler(btnLookupButton_MouseLeave);
				}
				else
				{
					_isInitialized = true;
					this.btnLookupButton.Source = new BitmapImage(new Uri("/LookupControl;component/Images/btn_off_lookup.png", UriKind.Relative));
					this.btnLookupButton.MouseLeftButtonUp += btnLookupButton_Click;
					this.lnkButton.Click += lnkButton_Click;
					this.icoLookupIcon.MouseLeftButtonUp += lnkButton_Click;
					this.LayoutRoot.MouseLeftButtonDown += LayoutRoot_MouseLeftButtonDown;
					this.btnLookupButton.MouseEnter += new MouseEventHandler(btnLookupButton_MouseEnter);
					this.btnLookupButton.MouseLeave += new MouseEventHandler(btnLookupButton_MouseLeave);
				}
			}
			List<HyperlinkButton> hlbuttons = new List<HyperlinkButton>();
			foreach (var item in this.Items)
			{
				item.Url = CombineUrl(XrmHelper.ServerUri, "/main.aspx?etc=" + this.ObjectTypeCode + "&id=" + item.Id.ToString() + "&pagetype=entityrecord").AbsoluteUri;
				HyperlinkButton hlbutton = new HyperlinkButton();
				hlbutton.Content = item.Name;
				hlbutton.NavigateUri = new Uri(item.Url);
				hlbuttons.Add(hlbutton);
			}
			if (this.Items.Count > 0)
			{
				domainUpDown1.ItemsSource = hlbuttons;
			}
			else
			{
				this.Items = new List<LookupItem>();
			}
			if (LookupControlLoaded != null)
			{
				RoutedEventArgs e = new RoutedEventArgs();
				this.Dispatcher.BeginInvoke(() => LookupControlLoaded(this, e));
			}
		}

		private void domainUpDown1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
		{
			if (e.NewValue != null)
			{
				HyperlinkButton btn = (HyperlinkButton)e.NewValue;
				this.lnkButton.Content = btn.Content;
			}
			else
			{
				this.lnkButton.Content = string.Empty;
			}
		}

		private void UserControl_Loaded(object sender, RoutedEventArgs e)
		{
			if (!DesignerProperties.IsInDesignTool && this.ObjectTypeCode == 0)
			{
				LoadEntity();
			}
			else
			{
				LookupLoaded();
			}
		}

		private void autoCompleteBox_Populating(object sender, PopulatingEventArgs e)
		{
			RetrieveAutoItemSource(e.Parameter);
		}

		private void RetrieveAutoItemSource(string prefix)
		{
			string searchCol = _searchAttribute == string.Empty ? _primaryAttribute : _searchAttribute;
			ObservableCollection<string> columns = new ObservableCollection<string>();
			columns.Add(_primaryAttribute);
			bool isFiltered = !string.IsNullOrEmpty(this.FilteredView.FetchXml);
			if (!isFiltered)
			{
				autoCompleteBox.FilterMode = AutoCompleteFilterMode.None;
				QueryExpression qe = new QueryExpression()
				{
					EntityName = this._oTypeName,
					ColumnSet = new ColumnSet() { Columns = columns },
					Criteria = new FilterExpression()
					{
						Conditions = new ObservableCollection<ConditionExpression>()
					{
						new ConditionExpression()
						{
							AttributeName=searchCol,Operator=ConditionOperator.BeginsWith,Values=new ObservableCollection<object>(){prefix},
						}
					}
					},
					PageInfo = new PagingInfo()
					{
						Count = 10,
						PageNumber = 1
					}
				};
				SoapHelper.BeginExecuteRetrieveMultiple(qe, RetrieveAutoItemSource_Callback);
			}
			else
			{
				autoCompleteBox.FilterMode = AutoCompleteFilterMode.StartsWith;
				FetchExpression qe = new FetchExpression() { Query = FilteredView.FetchXml };
				SoapHelper.BeginExecuteRetrieveMultiple(qe, RetrieveAutoItemSource_Callback);
			}
		}

		private void RetrieveAutoItemSource_Callback(IAsyncResult result)
		{
			try
			{
				List<AutoItem> items = new List<AutoItem>();
				OrganizationResponse response = ((IOrganizationService)result.AsyncState).EndExecute(result);
				EntityCollection results = response["EntityCollection"] as EntityCollection;
				foreach (var item in results.Entities)
				{
					AutoItem lookup = new AutoItem()
					{
						Name = item.GetAttributeValue<string>(_primaryAttribute),
						Id = item.Id,
						Icon = this.Icon
					};
					items.Add(lookup);
				}
				this.Dispatcher.BeginInvoke(() => autoCompleteBox.ItemsSource = items);
				this.Dispatcher.BeginInvoke(() => autoCompleteBox.PopulateComplete());
			}
			catch (Exception ex)
			{
				ReportError(ex);
			}
		}

		private void autoCompleteBox_DropDownClosed(object sender, RoutedPropertyChangedEventArgs<bool> e)
		{
			AutoItem newValue = (sender as AutoCompleteBox).SelectedItem as AutoItem;
			if (newValue != null)
			{
				this.Items = new List<LookupItem>() { new LookupItem() { Id = newValue.Id, Name = newValue.Name } };
				if (LookupControlOnUserChangeValue != null)
				{
					LookupControlOnUserChangeValue(this, new RoutedEventArgs());
				}
			}
		}

		private void autoCompleteBox_LostFocus(object sender, RoutedEventArgs e)
		{
			AutoItem newValue = (sender as AutoCompleteBox).SelectedItem as AutoItem;
			if (newValue != null)
			{
				this.Items = new List<LookupItem>() { new LookupItem() { Id = newValue.Id, Name = newValue.Name } };
				if (LookupControlOnUserChangeValue != null)
				{
					LookupControlOnUserChangeValue(this, new RoutedEventArgs());
				}
			}
			else
			{
				autoCompleteBox.Visibility = System.Windows.Visibility.Collapsed;
				lnkButton.Visibility = System.Windows.Visibility.Visible;
			}
		}

		private void autoCompleteBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			this.Focus();
			base.OnMouseLeftButtonDown(e);
		}

		/// <summary>
		/// Combines a URI with a relative URI
		/// </summary>
		/// <param name="baseUrl">Base (absolute) URI</param>
		/// <param name="path">Relative URI that is to be used</param>
		/// <returns>Combined URI</returns>
		private static Uri CombineUrl(Uri baseUrl, string path)
		{
			if (null == baseUrl)
			{
				throw new ArgumentNullException("baseUrl");
			}
			if (string.IsNullOrEmpty(path))
			{
				return baseUrl;
			}
			string url = baseUrl.AbsoluteUri;
			int end = url.Length - 1;
			// Check if there is a '/' at the beginning of path
			if (url[end] == '/' && path[0] == '/')
			{
				url = url.Substring(0, end);
			}
			else if (url[end] != '/' && path[0] != '/')
			{
				url += '/';
			}
			// Create the combined URL
			return new Uri(url + path);
		}

		private void autoCompleteBox_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Tab)
			{
				autoCompleteBox.Visibility = System.Windows.Visibility.Collapsed;
				lnkButton.Visibility = System.Windows.Visibility.Visible;
			}
		}
	}

	public class LookupItem
	{
		Guid _id;
		string _name;
		string _url;

		public Guid Id { get { return _id; } set { _id = value; } }

		public string Name { get { return _name; } set { _name = value; } }

		public string Url { get { return _url; } set { _url = value; } }
	}

	public class AutoItem
	{
		Guid _id;
		string _name;
		ImageSource _icon;

		public Guid Id { get { return _id; } set { _id = value; } }

		public string Name { get { return _name; } set { _name = value; } }

		public ImageSource Icon { get { return _icon; } set { _icon = value; } }
	}

	public class LookupView
	{
		string _objectTypeCode = string.Empty;
		Guid _id = Guid.Empty;
		string _name = string.Empty;
		string _fetchXml = string.Empty;
		string _layoutXml = string.Empty;

		public string ObjectTypeCode { get { return _objectTypeCode; } set { _objectTypeCode = value; } }

		public Guid ViewId { get { return _id; } set { _id = value; } }

		public string DisplayName { get { return _name; } set { _name = value; } }

		public string FetchXml { get { return _fetchXml; } set { _fetchXml = value; } }

		public string LayoutXml { get { return _layoutXml; } set { _layoutXml = value; } }
	}
}